package roborally.Pieces;
import be.kuleuven.cs.som.annotate.*;

/**
 * This is a class of Batteries that have an amount of Energy, a weight and possibly a Position on a Board.
 * @note Maximum amount of Energy of a Battery does not have to remain the same for each battery, but energy only decreases so field maxEnergy is not needed.
 * @invar | getEnergy() != null
 * @invar The position is valid 
 * 		| Position.isValidPosition(getPosition().getX(), getPosition().getY(), getPosition().getBoard() )
 * @version 2.0
 * @author Bart Opsomer 2de Bachelor Ingenieurswetenschappen Electrotechniek-Computerwetenschappen 
 * 		   Peter Opsomer 1ste Master Wiskundige IngenieursTechnieken
 */
public class Battery extends CarriablePiece {
	private Energy energy;
	/**
	 * Makes a new Battery with a given weight. If there were no changes to GamePieceWithoutOrientation (see its documentation), this Battery has no initial 
	 * position, so new.getPosition() == null: the battery is not owned by any robot and is not placed on a board.
	 * 
	 * @pre 	| maxEnergy != null
	 * @pre 	| energy != null
	 * @pre 	| maxEnergy.isGreaterThanOrEquals(energy)
	 * 
	 * @param 	weight the weight of this Battery
	 * @param 	energy the initial Energy of this Battery
	 * @param 	maxEnergy the maximum amount of energy in this Battery
	 * @effect 	| super(weight)
	 * @post   	| new.getEnergy().equals(energy)
	 */
	@Raw
	public Battery(int weight,Energy energy,Energy maxEnergy) {
		super(weight);
		assert(maxEnergy != null);
		assert(energy != null);
		assert(maxEnergy.isGreaterThanOrEquals(energy) );
		this.energy = energy;
	}
	/**
	 * Makes a new Battery with weight 1500gram, initial energy 5000Ws and maxEnergy 5000Ws.
	 * 
	 * @effect this(1500, new Energy(5000.0), new Energy(5000.0) )
	 */
	@Raw
	public Battery() {
		this(1500,new Energy(5000.0),new Energy(5000.0) );
	}
	/**
	 * @return the current energy of the battery
	 */
	@Basic
	public Energy getEnergy() {
		return energy;
	}
	/**
	 * Overrides the use method of the super class CarriablePiece
	 * @param 	robot the robot on which the item, is to be used
	 * @effect 	useBattery(robot)
	 */
	@Override
	public void use(Robot robot) {
		useBattery(robot);
	}
	/**
	 * Recharges the robot with the energy of the this battery. No precondition is necessary and this method doesn't do anything if the given Robot is null.
	 * 
	 * @param robot the robot to be recharged
	 * @effect| if( (robot != null) && this.isTerminated() ) then
	 * 		  |		robot.drop(this)
	 * @post  | this.getEnergy().increase(robot.getEnergy() ).compareTo(new.getEnergy().increase( (new robot).getEnergy() ) ) == 0
	 * @post  | if( (robot != null) && !this.isTerminated() ) then
	 * 		  |		new.getEnergy() == max(robot.getMaxEnergy().decrease(robot.getEnergy() ) , Energy.ZERO)
	 */
	public void useBattery(Robot robot) {
		if(robot == null)
			return;		
		// If the battery the robot is trying to use is	terminated, the battery must be discarded by the robot
		if(this.isTerminated()) {
			robot.drop(this);
		}
		Energy temp = new Energy(robot.getEnergy());
		Energy energyOfBattery = this.getEnergy();
		temp.increase(energyOfBattery);
		Energy leftOverEnergy = new Energy(0);
		if(robot.getMaxEnergy().isGreaterThanOrEquals(temp)) {
			//Recharges completely
			robot.getEnergy().increase(this.getEnergy());
			energyOfBattery.decrease(energyOfBattery);
			//Robot does not have to automatically drop Batteries when they are empty
		}
		else {
			// Recharge the robot until maxEnergy
			temp.decrease(robot.getMaxEnergy());
			energyOfBattery.decrease(temp);
			robot.getEnergy().increase(energyOfBattery);
			leftOverEnergy = temp;
		}
		// This means setting the energy twice because also energyOfBattery.decrease(...), just to be sure
		this.energy = leftOverEnergy;
	}
	/**
	 * Return a textual representation of this Battery for the GUI. This method gives information about the energy, weight and then the position of the Battery.
	 * 
	 * @return | result.equals("Battery with energy " + energy.toString() + super.toString() )
	 */
	@Override
	public String toString() {
		return "Battery with energy " + energy.toString() + super.toString();
	}
}
